<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>WebSocket Security :: Spring Security</title>
<link rel="canonical" href="../../../servlet/integrations/websocket.html">
<link rel="prev" href="mvc.html">
<link rel="next" href="cors.html">
<meta name="generator" content="Antora 3.0.0">
<link rel="stylesheet" href="../../../_/css/site.css">
<link href="../../../_/img/favicon.ico" rel='shortcut icon' type='image/vnd.microsoft.icon'>
<link rel="stylesheet" href="../../../_/css/vendor/docsearch.min.css">

<script>var uiRootPath = '../../../_'</script>
</head>
<body class="article">
<header class="header">
<nav class="navbar">
<div class="navbar-brand">
<a class="navbar-item" href="https://spring.io">
<img id="springlogo" class="block" src="../../../_/img/spring-logo.svg" alt="Spring">
</a>
<button class="navbar-burger" data-target="topbar-nav">
<span></span>
<span></span>
<span></span>
</button>
</div>
<div id="topbar-nav" class="navbar-menu">
<div class="navbar-end">
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="websocket.html#">Why Spring</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="https://spring.io/why-spring">Overview</a>
<a class="navbar-item" href="https://spring.io/microservices">Microservices</a>
<a class="navbar-item" href="https://spring.io/reactive">Reactive</a>
<a class="navbar-item" href="https://spring.io/event-driven">Event Driven</a>
<a class="navbar-item" href="https://spring.io/cloud">Cloud</a>
<a class="navbar-item" href="https://spring.io/web-applications">Web Applications</a>
<a class="navbar-item" href="https://spring.io/serverless">Serverless</a>
<a class="navbar-item" href="https://spring.io/batch">Batch</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="websocket.html#">Learn</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="https://spring.io/learn">Overview</a>
<a class="navbar-item" href="https://spring.io/quickstart">Quickstart</a>
<a class="navbar-item" href="https://spring.io/guides">Guides</a>
<a class="navbar-item" href="https://spring.io/blog">Blog</a>
</div>
</div>
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link" href="websocket.html#">Projects</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="https://spring.io/projects">Overview</a>
<a class="navbar-item" href="https://spring.io/projects/spring-boot">Spring Boot</a>
<a class="navbar-item" href="https://spring.io/projects/spring-framework">Spring Framework</a>
<a class="navbar-item" href="https://spring.io/projects/spring-cloud">Spring Cloud</a>
<a class="navbar-item" href="https://spring.io/projects/spring-cloud-dataflow">Spring Cloud Data Flow</a>
<a class="navbar-item" href="https://spring.io/projects/spring-data">Spring Data</a>
<a class="navbar-item" href="https://spring.io/projects/spring-integration">Spring Integration</a>
<a class="navbar-item" href="https://spring.io/projects/spring-batch">Spring Batch</a>
<a class="navbar-item" href="https://spring.io/projects/spring-security">Spring Security</a>
<a class="navbar-item navbar-item-special" href="https://spring.io/projects">View all projects</a>
<a class="navbar-item" href="https://spring.io/tools">Spring Tools 4</a>
<a class="navbar-item navbar-item-special-2" href="https://start.spring.io">Spring Initializr <svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><polyline points="15 10.94 15 15 1 15 1 1 5.06 1" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></polyline><polyline points="8.93 1 15 1 15 7.07" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></polyline><line x1="15" y1="1" x2="8" y2="8" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="2"></line></svg></a>
</div>
</div>
<a class="navbar-item" href="https://spring.io/training">Training</a>
<a class="navbar-item" href="https://spring.io/support">Support</a>
<div class="navbar-item has-dropdown is-hoverable is-community">
<a class="navbar-link" href="websocket.html#">Community</a>
<div class="navbar-dropdown">
<a class="navbar-item" href="https://spring.io/community">Overview</a>
<a class="navbar-item" href="https://spring.io/events">Events</a>
<a class="navbar-item" href="https://spring.io/team">Team</a>
</div>
</div>
</div>
</div>
<div id="switch-theme">
<input type="checkbox" id="switch-theme-checkbox" />
<label for="switch-theme-checkbox">Dark Theme</label>
</div>
</nav>
</header>
<div class="body">
<div class="nav-container" data-component="ROOT" data-version="5.6.0">
<aside class="nav">
<div class="panels">
<div class="nav-panel-menu is-active" data-panel="menu">
<nav class="nav-menu">
<h3 class="title"><a href="../../index.html">Spring Security</a></h3>
<ul class="nav-list">
<li class="nav-item" data-depth="0">
<ul class="nav-list">
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../index.html">Overview</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../prerequisites.html">Prerequisites</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../community.html">Community</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../whats-new.html">What&#8217;s New</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../getting-spring-security.html">Getting Spring Security</a>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../features/index.html">Features</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../features/authentication/index.html">Authentication</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/authentication/password-storage.html">Password Storage</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../features/exploits/index.html">Protection Against Exploits</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/exploits/csrf.html">CSRF</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/exploits/headers.html">HTTP Headers</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/exploits/http.html">HTTP Requests</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../features/integrations/index.html">Integrations</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/integrations/cryptography.html">Cryptography</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/integrations/data.html">Spring Data</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/integrations/concurrency.html">Java&#8217;s Concurrency APIs</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/integrations/jackson.html">Jackson</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../features/integrations/localization.html">Localization</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../modules.html">Project Modules</a>
</li>
<li class="nav-item" data-depth="1">
<a class="nav-link" href="../../samples.html">Samples</a>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../index.html">Servlet Applications</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../getting-started.html">Getting Started</a>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../architecture.html">Architecture</a>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../authentication/index.html">Authentication</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/architecture.html">Authentication Architecture</a>
</li>
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../authentication/passwords/index.html">Username/Password</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../authentication/passwords/input.html">Reading Username/Password</a>
<ul class="nav-list">
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/form.html">Form</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/basic.html">Basic</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/digest.html">Digest</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="4">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../authentication/passwords/storage.html">Password Storage</a>
<ul class="nav-list">
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/in-memory.html">In Memory</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/jdbc.html">JDBC</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/user-details.html">UserDetails</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/user-details-service.html">UserDetailsService</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/password-encoder.html">PasswordEncoder</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/dao-authentication-provider.html">DaoAuthenticationProvider</a>
</li>
<li class="nav-item" data-depth="5">
<a class="nav-link" href="../authentication/passwords/ldap.html">LDAP</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/session-management.html">Session Management</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/rememberme.html">Remember Me</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/openid.html">OpenID</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/anonymous.html">Anonymous</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/preauth.html">Pre-Authentication</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/jaas.html">JAAS</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/cas.html">CAS</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/x509.html">X509</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/runas.html">Run-As</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/logout.html">Logout</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authentication/events.html">Authentication Events</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../authorization/index.html">Authorization</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authorization/architecture.html">Authorization Architecture</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authorization/authorize-requests.html">Authorize HTTP Requests</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authorization/expression-based.html">Expression-Based Access Control</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authorization/secure-objects.html">Secure Object Implementations</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authorization/method-security.html">Method Security</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../authorization/acls.html">Domain Object Security ACLs</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../oauth2/index.html">OAuth2</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../oauth2/login/index.html">OAuth2 Log In</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../oauth2/login/core.html">Core Configuration</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../oauth2/login/advanced.html">Advanced Configuration</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../oauth2/client/index.html">OAuth2 Client</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../oauth2/client/core.html">Core Interfaces and Classes</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../oauth2/client/authorization-grants.html">OAuth2 Authorization Grants</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../oauth2/client/client-authentication.html">OAuth2 Client Authentication</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../oauth2/client/authorized-clients.html">OAuth2 Authorized Clients</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../oauth2/resource-server/index.html">OAuth2 Resource Server</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../oauth2/resource-server/jwt.html">JWT</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../oauth2/resource-server/opaque-token.html">Opaque Token</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../oauth2/resource-server/multitenancy.html">Multitenancy</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../oauth2/resource-server/bearer-tokens.html">Bearer Tokens</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../saml2/index.html">SAML2</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../saml2/login/index.html">SAML2 Log In</a>
<ul class="nav-list">
 <li class="nav-item" data-depth="4">
<a class="nav-link" href="../saml2/login/overview.html">SAML2 Log In Overview</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../saml2/login/authentication-requests.html">SAML2 Authentication Requests</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../saml2/login/authentication.html">SAML2 Authentication Responses</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../saml2/logout.html">SAML2 Logout</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../saml2/metadata.html">SAML2 Metadata</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../exploits/index.html">Protection Against Exploits</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../exploits/csrf.html">Cross Site Request Forgery (CSRF) for Servlet Environments</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../exploits/headers.html">Security HTTP Response Headers</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../exploits/http.html">HTTP</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../exploits/firewall.html">HttpFirewall</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="index.html">Integrations</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="concurrency.html">Concurrency</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="jackson.html">Jackson</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="localization.html">Localization</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="servlet-api.html">Servlet APIs</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="data.html">Spring Data</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="mvc.html">Spring MVC</a>
</li>
<li class="nav-item is-current-page" data-depth="3">
<a class="nav-link" href="websocket.html">WebSocket</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="cors.html">Spring&#8217;s CORS Support</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="jsp-taglibs.html">JSP Taglib</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<span class="nav-text">Configuration</span>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../configuration/java.html">Java Configuration</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../configuration/kotlin.html">Kotlin Configuration</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../configuration/xml-namespace.html">Namespace Configuration</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../test/index.html">Testing</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../test/method.html">Method Security</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../test/mockmvc/index.html">MockMvc Support</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../test/mockmvc/setup.html">MockMvc Setup</a>
</li>
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../test/mockmvc/request-post-processors.html">Security RequestPostProcessors</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../test/mockmvc/authentication.html">Mocking Users</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../test/mockmvc/csrf.html">Mocking CSRF</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../test/mockmvc/form-login.html">Mocking Form Login</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../test/mockmvc/http-basic.html">Mocking HTTP Basic</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../test/mockmvc/oauth2.html">Mocking OAuth2</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../test/mockmvc/logout.html">Mocking Logout</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../test/mockmvc/request-builders.html">Security RequestBuilders</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../test/mockmvc/result-matchers.html">Security ResultMatchers</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../test/mockmvc/result-handlers.html">Security ResultHandlers</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../appendix/index.html">Appendix</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../appendix/database-schema.html">Database Schemas</a>
</li>
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../appendix/namespace/index.html">XML Namespace</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../appendix/namespace/authentication-manager.html">Authentication Services</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../appendix/namespace/http.html">Web Security</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../appendix/namespace/method-security.html">Method Security</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../appendix/namespace/ldap.html">LDAP Security</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../appendix/namespace/websocket.html">WebSocket Security</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../appendix/faq.html">FAQ</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="1">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../reactive/index.html">Reactive Applications</a>
<ul class="nav-list">
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../reactive/getting-started.html">Getting Started</a>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<span class="nav-text">Authentication</span>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/authentication/x509.html">X.509 Authentication</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/authentication/logout.html">Logout</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<span class="nav-text">Authorization</span>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/authorization/method.html">EnableReactiveMethodSecurity</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../reactive/oauth2/index.html">OAuth2</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../reactive/oauth2/login/index.html">OAuth2 Log In</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/oauth2/login/core.html">Core Configuration</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/oauth2/login/advanced.html">Advanced Configuration</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../reactive/oauth2/client/index.html">OAuth2 Client</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/oauth2/client/core.html">Core Interfaces and Classes</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/oauth2/client/authorization-grants.html">OAuth2 Authorization Grants</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/oauth2/client/client-authentication.html">OAuth2 Client Authentication</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/oauth2/client/authorized-clients.html">OAuth2 Authorized Clients</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../reactive/oauth2/resource-server/index.html">OAuth2 Resource Server</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/oauth2/resource-server/jwt.html">JWT</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/oauth2/resource-server/opaque-token.html">Opaque Token</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/oauth2/resource-server/multitenancy.html">Multitenancy</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/oauth2/resource-server/bearer-tokens.html">Bearer Tokens</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../reactive/exploits/index.html">Protection Against Exploits</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/exploits/csrf.html">CSRF</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/exploits/headers.html">Headers</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/exploits/http.html">HTTP Requests</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<span class="nav-text">Integrations</span>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/integrations/cors.html">CORS</a>
</li>
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/integrations/rsocket.html">RSocket</a>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../reactive/test/index.html">Testing</a>
<ul class="nav-list">
<li class="nav-item" data-depth="3">
<a class="nav-link" href="../../reactive/test/method.html">Testing Method Security</a>
</li>
<li class="nav-item" data-depth="3">
<button class="nav-item-toggle"></button>
<a class="nav-link" href="../../reactive/test/web/index.html">Testing Web Security</a>
<ul class="nav-list">
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/test/web/setup.html">WebTestClient Setup</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/test/web/authentication.html">Testing Authentication</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/test/web/csrf.html">Testing CSRF</a>
</li>
<li class="nav-item" data-depth="4">
<a class="nav-link" href="../../reactive/test/web/oauth2.html">Testing OAuth 2.0</a>
</li>
</ul>
</li>
</ul>
</li>
<li class="nav-item" data-depth="2">
<a class="nav-link" href="../../reactive/configuration/webflux.html">WebFlux Security</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</div>
<div class="nav-panel-explore" data-panel="explore">
<div class="context">
<span class="title">Spring Security</span>
<span class="version">5.6.0</span>
</div>
<ul class="components">
<li class="component is-current">
<a class="title" href="../../../index.html">Spring Security</a>
<ul class="versions">
<li class="version">
<a href="../../../6.0/index.html">6.0.0-SNAPSHOT</a>
</li>
<li class="version">
<a href="../../../6.0.0-M3/index.html">6.0.0-M3</a>
</li>
<li class="version">
<a href="../../../6.0.0-M2/index.html">6.0.0-M2</a>
</li>
<li class="version">
<a href="../../../6.0.0-M1/index.html">6.0.0-M1</a>
</li>
<li class="version">
<a href="../../../5.7/index.html">5.7.0-SNAPSHOT</a>
</li>
<li class="version">
<a href="../../../5.7.0-RC1/index.html">5.7.0-RC1</a>
</li>
<li class="version">
<a href="../../../5.7.0-M3/index.html">5.7.0-M3</a>
</li>
<li class="version">
<a href="../../../5.7.0-M2/index.html">5.7.0-M2</a>
</li>
<li class="version">
<a href="../../../5.7.0-M1/index.html">5.7.0-M1</a>
</li>
<li class="version">
<a href="../../../5.6.4/index.html">5.6.4-SNAPSHOT</a>
</li>
<li class="version is-latest">
<a href="../../../index.html">5.6.3</a>
</li>
<li class="version">
<a href="../../../5.6.2/index.html">5.6.2</a>
</li>
<li class="version">
<a href="../../../5.6.1/index.html">5.6.1</a>
</li>
<li class="version is-current">
<a href="../../index.html">5.6.0</a>
</li>
<li class="version">
<a href="../../../5.6.0-RC1/index.html">5.6.0-RC1</a>
</li>
</ul>
</li>
</ul>
</div>
</div>
</aside>
</div>
<main class="article">
<div class="toolbar" role="navigation">
<button class="nav-toggle"></button>
<nav class="breadcrumbs" aria-label="breadcrumbs">
<ul>
<li><a href="../../index.html">Spring Security</a></li>
<li><a href="../index.html">Servlet Applications</a></li>
<li><a href="index.html">Integrations</a></li>
<li><a href="websocket.html">WebSocket</a></li>
</ul>
</nav>
<div class="search">
<input id="search-input" type="text" placeholder="Search docs">
</div>
<div class="page-versions">
<button class="version-menu-toggle" title="Show other versions of page">5.6.0</button>
<div class="version-menu">
<a class="version" href="../../../6.0/servlet/integrations/websocket.html">6.0.0-SNAPSHOT</a>
<a class="version" href="../../../6.0.0-M3/servlet/integrations/websocket.html">6.0.0-M3</a>
<a class="version" href="../../../6.0.0-M2/servlet/integrations/websocket.html">6.0.0-M2</a>
<a class="version" href="../../../6.0.0-M1/servlet/integrations/websocket.html">6.0.0-M1</a>
<a class="version" href="../../../5.7/servlet/integrations/websocket.html">5.7.0-SNAPSHOT</a>
<a class="version" href="../../../5.7.0-RC1/servlet/integrations/websocket.html">5.7.0-RC1</a>
<a class="version" href="../../../5.7.0-M3/servlet/integrations/websocket.html">5.7.0-M3</a>
<a class="version" href="../../../5.7.0-M2/servlet/integrations/websocket.html">5.7.0-M2</a>
<a class="version" href="../../../5.7.0-M1/servlet/integrations/websocket.html">5.7.0-M1</a>
<a class="version" href="../../../5.6.4/servlet/integrations/websocket.html">5.6.4-SNAPSHOT</a>
<a class="version" href="../../../servlet/integrations/websocket.html">5.6.3</a>
<a class="version" href="../../../5.6.2/servlet/integrations/websocket.html">5.6.2</a>
<a class="version" href="../../../5.6.1/servlet/integrations/websocket.html">5.6.1</a>
<a class="version is-current" href="websocket.html">5.6.0</a>
<a class="version" href="../../../5.6.0-RC1/servlet/integrations/websocket.html">5.6.0-RC1</a>
</div>
</div>
<div class="edit-this-page"><a href="https://github.com/spring-projects/spring-security/blob/5.6.0/docs/modules/ROOT/pages/servlet/integrations/websocket.adoc">Edit this Page</a></div>
</div>
<div class="content">
<aside class="toc sidebar" data-title="Contents" data-levels="2">
<div class="toc-menu"></div>
</aside>
<article class="doc">
<div class="admonitionblock important">
<table>
<tbody><tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
<div class="paragraph">
<p> For the latest stable version, please use <a href="../../../servlet/integrations/websocket.html">Spring Security 5.6.3</a>!</p>
</div>
</td>
</tr></tbody>
</table>
</div>
<h1 id="page-title" class="page">WebSocket Security</h1>
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Spring Security 4 added support for securing <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html">Spring&#8217;s WebSocket support</a>.
This section describes how to use Spring Security&#8217;s WebSocket support.</p>
</div>
<div class="sidebarblock">
<div class="content">
<div class="title">Direct JSR-356 Support</div>
<div class="paragraph">
<p>Spring Security does not provide direct JSR-356 support because doing so would provide little value.
This is because the format is unknown, so there is <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-intro-sub-protocol">little Spring can do to secure an unknown format</a>.
Additionally, JSR-356 does not provide a way to intercept messages, so security would be rather invasive.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="websocket-configuration"><a class="anchor" href="websocket.html#websocket-configuration"></a>WebSocket Configuration</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Spring Security 4.0 has introduced authorization support for WebSockets through the Spring Messaging abstraction.
To configure authorization using Java Configuration, simply extend the <code>AbstractSecurityWebSocketMessageBrokerConfigurer</code> and configure the <code>MessageSecurityMetadataSourceRegistry</code>.
For example:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Configuration
public class WebSocketSecurityConfig
      extends AbstractSecurityWebSocketMessageBrokerConfigurer { <i class="conum" data-value="1"></i><b>(1)</b> <i class="conum" data-value="2"></i><b>(2)</b>

    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages
                .simpDestMatchers("/user/**").authenticated() <i class="conum" data-value="3"></i><b>(3)</b>
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Configuration
open class WebSocketSecurityConfig : AbstractSecurityWebSocketMessageBrokerConfigurer() { <i class="conum" data-value="1"></i><b>(1)</b> <i class="conum" data-value="2"></i><b>(2)</b>
    override fun configureInbound(messages: MessageSecurityMetadataSourceRegistry) {
        messages.simpDestMatchers("/user/**").authenticated() <i class="conum" data-value="3"></i><b>(3)</b>
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>This will ensure that:</p>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Any inbound CONNECT message requires a valid CSRF token to enforce <a href="websocket.html#websocket-sameorigin">Same Origin Policy</a></td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>The SecurityContextHolder is populated with the user within the simpUser header attribute for any inbound request.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Our messages require the proper authorization. Specifically, any inbound message that starts with "/user/" will require ROLE_USER. Additional details on authorization can be found in <a href="websocket.html#websocket-authorization">WebSocket Authorization</a></td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Spring Security also provides <a href="../appendix/namespace/websocket.html#nsa-websocket-security" class="xref page">XML Namespace</a> support for securing WebSockets.
A comparable XML based configuration looks like the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;websocket-message-broker&gt; <i class="conum" data-value="1"></i><b>(1)</b> <i class="conum" data-value="2"></i><b>(2)</b>
    <i class="conum" data-value="3"></i><b>(3)</b>
    &lt;intercept-message pattern="/user/**" access="hasRole('USER')" /&gt;
&lt;/websocket-message-broker&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>This will ensure that:</p>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Any inbound CONNECT message requires a valid CSRF token to enforce <a href="websocket.html#websocket-sameorigin">Same Origin Policy</a></td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>The SecurityContextHolder is populated with the user within the simpUser header attribute for any inbound request.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Our messages require the proper authorization. Specifically, any inbound message that starts with "/user/" will require ROLE_USER. Additional details on authorization can be found in <a href="websocket.html#websocket-authorization">WebSocket Authorization</a></td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="websocket-authentication"><a class="anchor" href="websocket.html#websocket-authentication"></a>WebSocket Authentication</h2>
<div class="sectionbody">
<div class="paragraph">
<p>WebSockets reuse the same authentication information that is found in the HTTP request when the WebSocket connection was made.
This means that the <code>Principal</code> on the <code>HttpServletRequest</code> will be handed off to WebSockets.
If you are using Spring Security, the <code>Principal</code> on the <code>HttpServletRequest</code> is overridden automatically.</p>
</div>
<div class="paragraph">
<p>More concretely, to ensure a user has authenticated to your WebSocket application, all that is necessary is to ensure that you setup Spring Security to authenticate your HTTP based web application.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="websocket-authorization"><a class="anchor" href="websocket.html#websocket-authorization"></a>WebSocket Authorization</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Spring Security 4.0 has introduced authorization support for WebSockets through the Spring Messaging abstraction.
To configure authorization using Java Configuration, simply extend the <code>AbstractSecurityWebSocketMessageBrokerConfigurer</code> and configure the <code>MessageSecurityMetadataSourceRegistry</code>.
For example:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages
                .nullDestMatcher().authenticated() <i class="conum" data-value="1"></i><b>(1)</b>
                .simpSubscribeDestMatchers("/user/queue/errors").permitAll() <i class="conum" data-value="2"></i><b>(2)</b>
                .simpDestMatchers("/app/**").hasRole("USER") <i class="conum" data-value="3"></i><b>(3)</b>
                .simpSubscribeDestMatchers("/user/**", "/topic/friends/*").hasRole("USER") <i class="conum" data-value="4"></i><b>(4)</b>
                .simpTypeMatchers(MESSAGE, SUBSCRIBE).denyAll() <i class="conum" data-value="5"></i><b>(5)</b>
                .anyMessage().denyAll(); <i class="conum" data-value="6"></i><b>(6)</b>

    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Configuration
open class WebSocketSecurityConfig : AbstractSecurityWebSocketMessageBrokerConfigurer() {
    override fun configureInbound(messages: MessageSecurityMetadataSourceRegistry) {
        messages
            .nullDestMatcher().authenticated() <i class="conum" data-value="1"></i><b>(1)</b>
            .simpSubscribeDestMatchers("/user/queue/errors").permitAll() <i class="conum" data-value="2"></i><b>(2)</b>
            .simpDestMatchers("/app/**").hasRole("USER") <i class="conum" data-value="3"></i><b>(3)</b>
            .simpSubscribeDestMatchers("/user/**", "/topic/friends/*").hasRole("USER") <i class="conum" data-value="4"></i><b>(4)</b>
            .simpTypeMatchers(MESSAGE, SUBSCRIBE).denyAll() <i class="conum" data-value="5"></i><b>(5)</b>
            .anyMessage().denyAll() <i class="conum" data-value="6"></i><b>(6)</b>
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>This will ensure that:</p>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Any message without a destination (i.e. anything other than Message type of MESSAGE or SUBSCRIBE) will require the user to be authenticated</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Anyone can subscribe to /user/queue/errors</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Any message that has a destination starting with "/app/" will be require the user to have the role ROLE_USER</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Any message that starts with "/user/" or "/topic/friends/" that is of type SUBSCRIBE will require ROLE_USER</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>Any other message of type MESSAGE or SUBSCRIBE is rejected. Due to 6 we do not need this step, but it illustrates how one can match on specific message types.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>Any other Message is rejected. This is a good idea to ensure that you do not miss any messages.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Spring Security also provides <a href="../appendix/namespace/websocket.html#nsa-websocket-security" class="xref page">XML Namespace</a> support for securing WebSockets.
A comparable XML based configuration looks like the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;websocket-message-broker&gt;
    <i class="conum" data-value="1"></i><b>(1)</b>
    &lt;intercept-message type="CONNECT" access="permitAll" /&gt;
    &lt;intercept-message type="UNSUBSCRIBE" access="permitAll" /&gt;
    &lt;intercept-message type="DISCONNECT" access="permitAll" /&gt;

    &lt;intercept-message pattern="/user/queue/errors" type="SUBSCRIBE" access="permitAll" /&gt; <i class="conum" data-value="2"></i><b>(2)</b>
    &lt;intercept-message pattern="/app/**" access="hasRole('USER')" /&gt;      <i class="conum" data-value="3"></i><b>(3)</b>

    <i class="conum" data-value="4"></i><b>(4)</b>
    &lt;intercept-message pattern="/user/**" access="hasRole('USER')" /&gt;
    &lt;intercept-message pattern="/topic/friends/*" access="hasRole('USER')" /&gt;

    <i class="conum" data-value="5"></i><b>(5)</b>
    &lt;intercept-message type="MESSAGE" access="denyAll" /&gt;
    &lt;intercept-message type="SUBSCRIBE" access="denyAll" /&gt;

    &lt;intercept-message pattern="/**" access="denyAll" /&gt; <i class="conum" data-value="6"></i><b>(6)</b>
&lt;/websocket-message-broker&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>This will ensure that:</p>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Any message of type CONNECT, UNSUBSCRIBE, or DISCONNECT will require the user to be authenticated</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Anyone can subscribe to /user/queue/errors</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Any message that has a destination starting with "/app/" will be require the user to have the role ROLE_USER</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Any message that starts with "/user/" or "/topic/friends/" that is of type SUBSCRIBE will require ROLE_USER</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>Any other message of type MESSAGE or SUBSCRIBE is rejected. Due to 6 we do not need this step, but it illustrates how one can match on specific message types.</td>
</tr>
<tr>
<td><i class="conum" data-value="6"></i><b>6</b></td>
<td>Any other message with a destination is rejected. This is a good idea to ensure that you do not miss any messages.</td>
</tr>
</table>
</div>
<div class="sect2">
<h3 id="websocket-authorization-notes"><a class="anchor" href="websocket.html#websocket-authorization-notes"></a>WebSocket Authorization Notes</h3>
<div class="paragraph">
<p>In order to properly secure your application it is important to understand Spring&#8217;s WebSocket support.</p>
</div>
<div class="sect3">
<h4 id="websocket-authorization-notes-messagetypes"><a class="anchor" href="websocket.html#websocket-authorization-notes-messagetypes"></a>WebSocket Authorization on Message Types</h4>
<div class="paragraph">
<p>It is important to understand the distinction between SUBSCRIBE and MESSAGE types of messages and how it works within Spring.</p>
</div>
<div class="paragraph">
<p>Consider a chat application.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The system can send notifications MESSAGE to all users through a destination of "/topic/system/notifications"</p>
</li>
<li>
<p>Clients can receive notifications by SUBSCRIBE to the "/topic/system/notifications".</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>While we want clients to be able to SUBSCRIBE to "/topic/system/notifications", we do not want to enable them to send a MESSAGE to that destination.
If we allowed sending a MESSAGE to "/topic/system/notifications", then clients could send a message directly to that endpoint and impersonate the system.</p>
</div>
<div class="paragraph">
<p>In general, it is common for applications to deny any MESSAGE sent to a destination that starts with the <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp">broker prefix</a> (i.e. "/topic/" or "/queue/").</p>
</div>
</div>
<div class="sect3">
<h4 id="websocket-authorization-notes-destinations"><a class="anchor" href="websocket.html#websocket-authorization-notes-destinations"></a>WebSocket Authorization on Destinations</h4>
<div class="paragraph">
<p>It is also is important to understand how destinations are transformed.</p>
</div>
<div class="paragraph">
<p>Consider a chat application.</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Users can send messages to a specific user by sending a message to the destination of "/app/chat".</p>
</li>
<li>
<p>The application sees the message, ensures that the "from" attribute is specified as the current user (we cannot trust the client).</p>
</li>
<li>
<p>The application then sends the message to the recipient using <code>SimpMessageSendingOperations.convertAndSendToUser("toUser", "/queue/messages", message)</code>.</p>
</li>
<li>
<p>The message gets turned into the destination of "/queue/user/messages-&lt;sessionid&gt;"</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>With the application above, we want to allow our client to listen to "/user/queue" which is transformed into "/queue/user/messages-&lt;sessionid&gt;".
However, we do not want the client to be able to listen to "/queue/*" because that would allow the client to see messages for every user.</p>
</div>
<div class="paragraph">
<p>In general, it is common for applications to deny any SUBSCRIBE sent to a message that starts with the <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp">broker prefix</a> (i.e. "/topic/" or "/queue/").
Of course we may provide exceptions to account for things like</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="websocket-authorization-notes-outbound"><a class="anchor" href="websocket.html#websocket-authorization-notes-outbound"></a>Outbound Messages</h3>
<div class="paragraph">
<p>Spring contains a section titled <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp-message-flow">Flow of Messages</a> that describes how messages flow through the system.
It is important to note that Spring Security only secures the <code>clientInboundChannel</code>.
Spring Security does not attempt to secure the <code>clientOutboundChannel</code>.</p>
</div>
<div class="paragraph">
<p>The most important reason for this is performance.
For every message that goes in, there are typically many more that go out.
Instead of securing the outbound messages, we encourage securing the subscription to the endpoints.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="websocket-sameorigin"><a class="anchor" href="websocket.html#websocket-sameorigin"></a>Enforcing Same Origin Policy</h2>
<div class="sectionbody">
<div class="paragraph">
<p>It is important to emphasize that the browser does not enforce the <a href="https://en.wikipedia.org/wiki/Same-origin_policy">Same Origin Policy</a> for WebSocket connections.
This is an extremely important consideration.</p>
</div>
<div class="sect2">
<h3 id="websocket-sameorigin-why"><a class="anchor" href="websocket.html#websocket-sameorigin-why"></a>Why Same Origin?</h3>
<div class="paragraph">
<p>Consider the following scenario.
A user visits bank.com and authenticates to their account.
The same user opens another tab in their browser and visits evil.com.
The Same Origin Policy ensures that evil.com cannot read or write data to bank.com.</p>
</div>
<div class="paragraph">
<p>With WebSockets the Same Origin Policy does not apply.
In fact, unless bank.com explicitly forbids it, evil.com can read and write data on behalf of the user.
This means that anything the user can do over the webSocket (i.e. transfer money), evil.com can do on that users behalf.</p>
</div>
<div class="paragraph">
<p>Since SockJS tries to emulate WebSockets it also bypasses the Same Origin Policy.
This means developers need to explicitly protect their applications from external domains when using SockJS.</p>
</div>
</div>
<div class="sect2">
<h3 id="websocket-sameorigin-spring"><a class="anchor" href="websocket.html#websocket-sameorigin-spring"></a>Spring WebSocket Allowed Origin</h3>
<div class="paragraph">
<p>Fortunately, since Spring 4.1.5 Spring&#8217;s WebSocket and SockJS support restricts access to the <a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-server-allowed-origins">current domain</a>.
Spring Security adds an additional layer of protection to provide <a href="https://en.wikipedia.org/wiki/Defense_in_depth_(computing)">defence in depth</a>.</p>
</div>
</div>
<div class="sect2">
<h3 id="websocket-sameorigin-csrf"><a class="anchor" href="websocket.html#websocket-sameorigin-csrf"></a>Adding CSRF to Stomp Headers</h3>
<div class="paragraph">
<p>By default Spring Security requires the <a href="../../features/exploits/csrf.html#csrf" class="xref page">CSRF token</a> in any CONNECT message type.
This ensures that only a site that has access to the CSRF token can connect.
Since only the <strong>Same Origin</strong> can access the CSRF token, external domains are not allowed to make a connection.</p>
</div>
<div class="paragraph">
<p>Typically we need to include the CSRF token in an HTTP header or an HTTP parameter.
However, SockJS does not allow for these options.
Instead, we must include the token in the Stomp headers</p>
</div>
<div class="paragraph">
<p>Applications can <a href="../exploits/csrf.html#servlet-csrf-include" class="xref page">obtain a CSRF token</a> by accessing the request attribute named _csrf.
For example, the following will allow accessing the <code>CsrfToken</code> in a JSP:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-javascript hljs" data-lang="javascript">var headerName = "${_csrf.headerName}";
var token = "${_csrf.token}";</code></pre>
</div>
</div>
<div class="paragraph">
<p>If you are using static HTML, you can expose the <code>CsrfToken</code> on a REST endpoint.
For example, the following would expose the <code>CsrfToken</code> on the URL /csrf</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@RestController
public class CsrfController {

    @RequestMapping("/csrf")
    public CsrfToken csrf(CsrfToken token) {
        return token;
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@RestController
class CsrfController {
    @RequestMapping("/csrf")
    fun csrf(token: CsrfToken): CsrfToken {
        return token
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>The JavaScript can make a REST call to the endpoint and use the response to populate the headerName and the token.</p>
</div>
<div class="paragraph">
<p>We can now include the token in our Stomp client.
For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-javascript hljs" data-lang="javascript">...
var headers = {};
headers[headerName] = token;
stompClient.connect(headers, function(frame) {
  ...

}</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="websocket-sameorigin-disable"><a class="anchor" href="websocket.html#websocket-sameorigin-disable"></a>Disable CSRF within WebSockets</h3>
<div class="paragraph">
<p>If you want to allow other domains to access your site, you can disable Spring Security&#8217;s protection.
For example, in Java Configuration you can use the following:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

    ...

    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Configuration
open class WebSocketSecurityConfig : AbstractSecurityWebSocketMessageBrokerConfigurer() {

    // ...

    override fun sameOriginDisabled(): Boolean {
        return true
    }
}</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="websocket-sockjs"><a class="anchor" href="websocket.html#websocket-sockjs"></a>Working with SockJS</h2>
<div class="sectionbody">
<div class="paragraph">
<p><a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-fallback">SockJS</a> provides fallback transports to support older browsers.
When using the fallback options we need to relax a few security constraints to allow SockJS to work with Spring Security.</p>
</div>
<div class="sect2">
<h3 id="websocket-sockjs-sameorigin"><a class="anchor" href="websocket.html#websocket-sockjs-sameorigin"></a>SockJS &amp; frame-options</h3>
<div class="paragraph">
<p>SockJS may use an <a href="https://github.com/sockjs/sockjs-client/tree/v0.3.4">transport that leverages an iframe</a>.
By default Spring Security will <a href="../../features/exploits/headers.html#headers-frame-options" class="xref page">deny</a> the site from being framed to prevent Clickjacking attacks.
To allow SockJS frame based transports to work, we need to configure Spring Security to allow the same origin to frame the content.</p>
</div>
<div class="paragraph">
<p>You can customize X-Frame-Options with the <a href="../appendix/namespace/http.html#nsa-frame-options" class="xref page">frame-options</a> element.
For example, the following will instruct Spring Security to use "X-Frame-Options: SAMEORIGIN" which allows iframes within the same domain:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http&gt;
    &lt;!-- ... --&gt;

    &lt;headers&gt;
        &lt;frame-options
          policy="SAMEORIGIN" /&gt;
    &lt;/headers&gt;
&lt;/http&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>Similarly, you can customize frame options to use the same origin within Java Configuration using the following:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@EnableWebSecurity
public class WebSecurityConfig extends
   WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // ...
            .headers(headers -&gt; headers
                .frameOptions(frameOptions -&gt; frameOptions
                     .sameOrigin()
                )
        );
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@EnableWebSecurity
open class WebSecurityConfig : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http {
            // ...
            headers {
                frameOptions {
                    sameOrigin = true
                }
            }
        }
    }
}</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="websocket-sockjs-csrf"><a class="anchor" href="websocket.html#websocket-sockjs-csrf"></a>SockJS &amp; Relaxing CSRF</h3>
<div class="paragraph">
<p>SockJS uses a POST on the CONNECT messages for any HTTP based transport.
Typically we need to include the CSRF token in an HTTP header or an HTTP parameter.
However, SockJS does not allow for these options.
Instead, we must include the token in the Stomp headers as described in <a href="websocket.html#websocket-sameorigin-csrf">Adding CSRF to Stomp Headers</a>.</p>
</div>
<div class="paragraph">
<p>It also means we need to relax our CSRF protection with the web layer.
Specifically, we want to disable CSRF protection for our connect URLs.
We do NOT want to disable CSRF protection for every URL.
Otherwise our site will be vulnerable to CSRF attacks.</p>
</div>
<div class="paragraph">
<p>We can easily achieve this by providing a CSRF RequestMatcher.
Our Java Configuration makes this extremely easy.
For example, if our stomp endpoint is "/chat" we can disable CSRF protection for only URLs that start with "/chat/" using the following configuration:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Configuration
@EnableWebSecurity
public class WebSecurityConfig
    extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -&gt; csrf
                // ignore our stomp endpoints since they are protected using Stomp headers
                .ignoringAntMatchers("/chat/**")
            )
            .headers(headers -&gt; headers
                // allow same origin to frame our site to support iframe SockJS
                .frameOptions(frameOptions -&gt; frameOptions
                    .sameOrigin()
                )
            )
            .authorizeHttpRequests(authorize -&gt; authorize
                ...
            )
            ...</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="highlightjs highlight"><code class="language-kotlin hljs" data-lang="kotlin">@Configuration
@EnableWebSecurity
open class WebSecurityConfig : WebSecurityConfigurerAdapter() {
    override fun configure(http: HttpSecurity) {
        http {
            csrf {
                ignoringAntMatchers("/chat/**")
            }
            headers {
                frameOptions {
                    sameOrigin = true
                }
            }
            authorizeRequests {
                // ...
            }
            // ...</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>If we are using XML based configuration, we can use the <a href="../appendix/namespace/http.html#nsa-csrf-request-matcher-ref" class="xref page"><span class="__cf_email__" data-cfemail="e281919084a290879397879196cf8f8396818a8790cf908784">[email&#160;protected]</span></a>.
For example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml">&lt;http ...&gt;
    &lt;csrf request-matcher-ref="csrfMatcher"/&gt;

    &lt;headers&gt;
        &lt;frame-options policy="SAMEORIGIN"/&gt;
    &lt;/headers&gt;

    ...
&lt;/http&gt;

&lt;b:bean id="csrfMatcher"
    class="AndRequestMatcher"&gt;
    &lt;b:constructor-arg value="#{T(org.springframework.security.web.csrf.CsrfFilter).DEFAULT_CSRF_MATCHER}"/&gt;
    &lt;b:constructor-arg&gt;
        &lt;b:bean class="org.springframework.security.web.util.matcher.NegatedRequestMatcher"&gt;
          &lt;b:bean class="org.springframework.security.web.util.matcher.AntPathRequestMatcher"&gt;
            &lt;b:constructor-arg value="/chat/**"/&gt;
          &lt;/b:bean&gt;
        &lt;/b:bean&gt;
    &lt;/b:constructor-arg&gt;
&lt;/b:bean&gt;</code></pre>
</div>
</div>
</div>
</div>
</div>
<nav class="pagination">
<span class="prev"><a href="mvc.html">Spring MVC</a></span>
<span class="next"><a href="cors.html">Spring&#8217;s CORS Support</a></span>
</nav>
</article>
</div>
</main>
</div>
<footer class="footer flex">
<div id="spring-links flex">
<img id="springlogo" src="../../../_/img/spring-logo.svg" alt="Spring">
<p class="smallest antialiased">© <script data-cfasync="false" src="https://docs.spring.io/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script>var d = new Date();
        document.write(d.getFullYear());</script> <a href="https://www.vmware.com/">VMware</a>, Inc. or its affiliates. <a href="https://www.vmware.com/help/legal.html">Terms of Use</a> • <a href="https://www.vmware.com/help/privacy.html" rel="noopener noreferrer">Privacy</a> • <a href="https://spring.io/trademarks">Trademark Guidelines</a> <span id="thank-you-mobile">• <a href="https://spring.io/thank-you">Thank you</a></span> • <a href="https://www.vmware.com/help/privacy/california-privacy-rights.html">Your California Privacy Rights</a> • <a class="ot-sdk-show-settings">Cookie Settings</a> <span id="teconsent"></span></p>
<p class="smallest antialiased">Apache®, Apache Tomcat®, Apache Kafka®, Apache Cassandra&trade;, and Apache Geode&trade; are trademarks or registered trademarks of the Apache Software Foundation in the United States and/or other countries. Java&trade;, Java&trade; SE, Java&trade; EE, and OpenJDK&trade; are trademarks of Oracle and/or its affiliates. Kubernetes® is a registered trademark of the Linux Foundation in the United States and other countries. Linux® is the registered trademark of Linus Torvalds in the United States and other countries. Windows® and Microsoft® Azure are registered trademarks of Microsoft Corporation. “AWS” and “Amazon Web Services” are trademarks or registered trademarks of Amazon.com Inc. or its affiliates. All other trademarks and copyrights are property of their respective owners and are only mentioned for informative purposes. Other names may be trademarks of their respective owners.</p>
</div>
<div id="social-icons" class="flex jc-between">
<a href="https://www.youtube.com/user/SpringSourceDev" title="Youtube"><svg id="youtube-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40"><circle class="cls-1" cx="20" cy="20" r="20" /><path class="cls-2" d="M30.91,14.53a2.89,2.89,0,0,0-2-2C27.12,12,20,12,20,12s-7.12,0-8.9.47a2.9,2.9,0,0,0-2,2A30.56,30.56,0,0,0,8.63,20a30.44,30.44,0,0,0,.46,5.47,2.89,2.89,0,0,0,2,2C12.9,28,20,28,20,28s7.12,0,8.9-.47a2.87,2.87,0,0,0,2-2A30.56,30.56,0,0,0,31.37,20,28.88,28.88,0,0,0,30.91,14.53ZM17.73,23.41V16.59L23.65,20Z" /></svg></a>
<a href="https://github.com/spring-projects" title="Github"><svg id="github-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 75.93 75.93"><path class="cls-1" d="M38,0a38,38,0,1,0,38,38A38,38,0,0,0,38,0Z" /></g><path class="cls-2" d="M38,15.59A22.95,22.95,0,0,0,30.71,60.3c1.15.21,1.57-.5,1.57-1.11s0-2,0-3.9c-6.38,1.39-7.73-3.07-7.73-3.07A6.09,6.09,0,0,0,22,48.86c-2.09-1.42.15-1.39.15-1.39a4.81,4.81,0,0,1,3.52,2.36c2,3.5,5.37,2.49,6.67,1.91a4.87,4.87,0,0,1,1.46-3.07c-5.09-.58-10.45-2.55-10.45-11.34a8.84,8.84,0,0,1,2.36-6.15,8.29,8.29,0,0,1,.23-6.07s1.92-.62,6.3,2.35a21.82,21.82,0,0,1,11.49,0c4.38-3,6.3-2.35,6.3-2.35a8.29,8.29,0,0,1,.23,6.07,8.84,8.84,0,0,1,2.36,6.15c0,8.81-5.37,10.75-10.48,11.32a5.46,5.46,0,0,1,1.56,4.25c0,3.07,0,5.54,0,6.29s.42,1.33,1.58,1.1A22.94,22.94,0,0,0,38,15.59Z" /></svg></a>
<a href="https://twitter.com/springcentral" title="Twitter"><svg id="twitter-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 75.93 75.93"><circle class="cls-1" cx="37.97" cy="37.97" r="37.97" /><path id="Twitter-2" data-name="Twitter" class="cls-2" d="M55.2,22.73a15.43,15.43,0,0,1-4.88,1.91,7.56,7.56,0,0,0-5.61-2.49A7.78,7.78,0,0,0,37,30a7.56,7.56,0,0,0,.2,1.79,21.63,21.63,0,0,1-15.84-8.23,8,8,0,0,0,2.37,10.52,7.66,7.66,0,0,1-3.48-1v.09A7.84,7.84,0,0,0,26.45,41a7.54,7.54,0,0,1-2,.28A7.64,7.64,0,0,1,23,41.09a7.71,7.71,0,0,0,7.18,5.47,15.21,15.21,0,0,1-9.55,3.37,15.78,15.78,0,0,1-1.83-.11,21.41,21.41,0,0,0,11.78,3.54c14.13,0,21.86-12,21.86-22.42,0-.34,0-.68,0-1a15.67,15.67,0,0,0,3.83-4.08,14.9,14.9,0,0,1-4.41,1.24A7.8,7.8,0,0,0,55.2,22.73Z" /></svg></a>
</div>
</footer>
<script src="../../../_/js/site.js"></script>
<script async src="../../../_/js/vendor/highlight.js"></script>
<script async src="../../../_/js/vendor/tabs.js"></script>
<script src="../../../_/js/vendor/switchtheme.js"></script>
<script src="../../../_/js/vendor/docsearch.min.js"></script>

<script>
var search = docsearch({
  appId: '244V8V9FGG',
  apiKey: '82c7ead946afbac3cf98c32446154691',
  indexName: 'security-docs',
  inputSelector: '#search-input',
  autocompleteOptions: { hint: false, keyboardShortcuts: ['s'] },
  algoliaOptions: { hitsPerPage: 10 }
}).autocomplete
search.on('autocomplete:closed', function () { search.autocomplete.setVal() })
</script>
<script>if (window.parent == window) {(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga');ga('create', 'UA-2728886-23', 'auto', {'siteSpeedSampleRate': 100});ga('send', 'pageview');}</script><script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"702d54c8f891642c","token":"bffcb8a918ae4755926f76178bfbd26b","version":"2021.12.0","si":100}' crossorigin="anonymous"></script>
</body>
</html>
